import UIKit

/* 协议 */
// 1
protocol Ownership {
    var owner: String {get}
    var registerDate: String {get}
    var serialNo: String {get}
    
    func updateOwnership(newOwner: String, newRegisterDate: String)
}

// 2
protocol Vehicle {
    var license: String {get}
    var producer: String {get}
    
    var speed: Int {get}
    var hour: Int {get}
    
    associatedtype weightType
    var weight: weightType {get}
    
    var distance: Int {get set}
    
    func movingVehicle(addHour: Int)
}

// 3
class Car: Ownership, Vehicle {
    var owner: String
    var registerDate: String
    var serialNo: String

    var license: String
    var producer: String
    var speed: Int
    var hour: Int
    var weight: Double
    
    var distance: Int {
        get {
            speed * hour
        }
        set {
            hour = newValue / speed
        }
    }
    
    func updateOwnership(newOwner: String, newRegisterDate: String) {
        self.owner = newOwner
        self.registerDate = newRegisterDate
    }
    
    func movingVehicle(addHour: Int) {
        self.hour += addHour
    }
    
    init() {
        self.owner = "Unknown"
        self.registerDate = "Unknown"
        self.serialNo = "Unknown"
        self.license = "Unknown"
        self.producer = "Unknown"
        self.speed = 0
        self.hour = 0
        self.weight = 0.0
    }
    
    init(owner: String, registerDate: String, serialNo: String, license: String, producer: String, speed: Int, hour: Int, weight: Double) {
        self.owner = owner
        self.registerDate = registerDate
        self.serialNo = serialNo
        self.license = license
        self.producer = producer
        self.speed = speed
        self.hour = hour
        self.weight = weight
    }
}

// 4
let myCar = Car(owner: "owner1", registerDate: "2023-01-01", serialNo: "123456", license: "123456", producer: "Volkswagon", speed: 120, hour: 0, weight: 1000.0)
myCar.movingVehicle(addHour: 800)
print(myCar.distance)

print(myCar.owner)
myCar.updateOwnership(newOwner: "owner2", newRegisterDate: "2023-09-01")
print(myCar.owner)

// 5
protocol New_Ownership {
    func updateOwnership(newOwner: String, newRegisterDate: String)
}

protocol New_Vehicle {
    func movingVehicle(addHour: Int)
}

class New_Car{
    var owner: String
    var registerDate: String
    var serialNo: String

    var license: String
    var producer: String
    var speed: Int
    var hour: Int
    var weight: Double
    
    var distance: Int {
        get {
            speed * hour
        }
        set {
            hour = newValue / speed
        }
    }
    
    init() {
        self.owner = "Unknown"
        self.registerDate = "Unknown"
        self.serialNo = "Unknown"
        self.license = "Unknown"
        self.producer = "Unknown"
        self.speed = 0
        self.hour = 0
        self.weight = 0.0
    }
    
    init(owner: String, registerDate: String, serialNo: String, license: String, producer: String, speed: Int, hour: Int, weight: Double) {
        self.owner = owner
        self.registerDate = registerDate
        self.serialNo = serialNo
        self.license = license
        self.producer = producer
        self.speed = speed
        self.hour = hour
        self.weight = weight
    }
}

extension New_Car: New_Ownership, New_Vehicle {
    func updateOwnership(newOwner: String, newRegisterDate: String) {
        self.owner = newOwner
        self.registerDate = newRegisterDate
    }
    
    func movingVehicle(addHour: Int) {
        self.hour += addHour
    }
}

let myNewCar = New_Car(owner: "owner1", registerDate: "2023-01-01", serialNo: "123456", license: "123456", producer: "Volkswagon", speed: 120, hour: 0, weight: 1000.0)
myNewCar.movingVehicle(addHour: 800)
print(myNewCar.distance)

print(myNewCar.owner)
myNewCar.updateOwnership(newOwner: "owner2", newRegisterDate: "2023-09-01")
print(myCar.owner)


/* 泛型 */
// 1
func swap2Element<A, B>(a: inout A, b: inout B) -> (B, A) {
    return (b, a)
}

var swap_a: Int = 33
var swap_b: String = "Jay"

print(swap2Element(a: &swap_a, b: &swap_b))

// 2
class Person<Weight, Height> {
    var name: String
    var weight: Weight
    var height: Height
    
    init(name: String, weight: Weight, height: Height) {
        self.name = name
        self.weight = weight
        self.height = height
    }
    
    func description() {
        print("name:\(name) weight:\(weight) height:\(height)")
    }
}

let person1 = Person(name: "Jennie", weight: 45, height: 160)
let person2 = Person(name: "Jack", weight: 69.2, height: 173)
let person3 = Person(name: "Sam", weight: 88.8, height: "Unknown")

person1.description()
person2.description()
person3.description()
